<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG 贝塞尔曲线研究</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            max-width: 800px;
        }

        .canvas-container {
            border: 1px solid #ccc;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        .controls {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            padding: 15px;
            border: 1px solid #eee;
            border-radius: 5px;
            background-color: #f9f9f9;
            width: 100%;
        }

        .control-group {
            display: flex;
            gap: 10px;
            align-items: center;
        }

        .control-group label {
            min-width: 80px;
            font-weight: bold;
        }

        input {
            width: 60px;
            padding: 5px;
        }

        button {
            padding: 8px 15px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 14px;
            grid-column: span 2;
        }

        button:hover {
            background-color: #45a049;
        }

        .info {
            margin-top: 10px;
            color: #666;
            font-size: 14px;
            width: 100%;
        }

        .point-label {
            position: absolute;
            font-size: 12px;
            background: rgba(255, 255, 255, 0.8);
            padding: 2px 5px;
            border-radius: 3px;
        }

        @media (max-width: 700px) {
            .controls {
                grid-template-columns: 1fr;
            }

            button {
                grid-column: span 1;
            }
        }
    </style>
</head>

<body>
    <h1>SVG 贝塞尔曲线研究</h1>

    <div class="container">
        <div class="canvas-container">
            <svg id="svgCanvas" width="600" height="400">
                <!-- 背景网格 -->
                <defs>
                    <pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse">
                        <path d="M 50 0 L 0 0 0 50" fill="none" stroke="#eee" stroke-width="1" />
                    </pattern>
                </defs>
                <rect width="100%" height="100%" fill="url(#grid)" />

                <!-- 贝塞尔曲线 -->
                <path id="bezierCurve" d="M100,200 C150,100 250,300 300,200" fill="none" stroke="blue"
                    stroke-width="3" />

                <!-- 控制点和连线 -->
                <line id="line1" x1="100" y1="200" x2="150" y2="100" stroke="#aaa" stroke-dasharray="5,5" />
                <line id="line2" x1="250" y1="300" x2="300" y2="200" stroke="#aaa" stroke-dasharray="5,5" />

                <!-- 起点和终点 -->
                <circle id="startPoint" cx="100" cy="200" r="6" fill="red" stroke="#333" stroke-width="1" />
                <circle id="endPoint" cx="300" cy="200" r="6" fill="red" stroke="#333" stroke-width="1" />

                <!-- 控制点 -->
                <circle id="control1" cx="150" cy="100" r="6" fill="green" stroke="#333" stroke-width="1" />
                <circle id="control2" cx="250" cy="300" r="6" fill="green" stroke="#333" stroke-width="1" />

                <!-- 坐标标签 -->
                <!-- <foreignObject id="startLabel" x="100" y="200" width="60" height="30" class="point-label">
                    <div xmlns="http://www.w3.org/1999/xhtml">(100, 200)</div>
                </foreignObject>
                <foreignObject id="endLabel" x="300" y="200" width="60" height="30" class="point-label">
                    <div xmlns="http://www.w3.org/1999/xhtml">(300, 200)</div>
                </foreignObject>
                <foreignObject id="control1Label" x="150" y="100" width="60" height="30" class="point-label">
                    <div xmlns="http://www.w3.org/1999/xhtml">(150, 100)</div>
                </foreignObject>
                <foreignObject id="control2Label" x="250" y="300" width="60" height="30" class="point-label">
                    <div xmlns="http://www.w3.org/1999/xhtml">(250, 300)</div>
                </foreignObject> -->
            </svg>
        </div>

        <div class="controls">
            <div class="control-group">
                <label>起点 X:</label>
                <input type="number" id="startX" value="100" min="0" max="600">
            </div>
            <div class="control-group">
                <label>起点 Y:</label>
                <input type="number" id="startY" value="200" min="0" max="400">
            </div>

            <div class="control-group">
                <label>控制点1 X:</label>
                <input type="number" id="cp1x" value="150" min="0" max="600">
            </div>
            <div class="control-group">
                <label>控制点1 Y:</label>
                <input type="number" id="cp1y" value="100" min="0" max="400">
            </div>

            <div class="control-group">
                <label>控制点2 X:</label>
                <input type="number" id="cp2x" value="250" min="0" max="600">
            </div>
            <div class="control-group">
                <label>控制点2 Y:</label>
                <input type="number" id="cp2y" value="300" min="0" max="400">
            </div>

            <div class="control-group">
                <label>终点 X:</label>
                <input type="number" id="endX" value="300" min="0" max="600">
            </div>
            <div class="control-group">
                <label>终点 Y:</label>
                <input type="number" id="endY" value="200" min="0" max="400">
            </div>

            <button id="updateBtn">更新曲线</button>
        </div>

        <div class="info">
            <p>这是一个三次贝塞尔曲线示例，使用 SVG 的 &lt;path&gt; 元素和 "C" 命令绘制。</p>
            <p>拖动控制点或修改坐标值来观察曲线变化。</p>
            <p>当前路径数据: <code id="pathData">M100,200 C150,100 250,300 300,200</code></p>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const svg = document.getElementById('svgCanvas');
            const bezierCurve = document.getElementById('bezierCurve');
            const startPoint = document.getElementById('startPoint');
            const endPoint = document.getElementById('endPoint');
            const control1 = document.getElementById('control1');
            const control2 = document.getElementById('control2');
            const line1 = document.getElementById('line1');
            const line2 = document.getElementById('line2');

            // 坐标输入框
            const startX = document.getElementById('startX');
            const startY = document.getElementById('startY');
            const cp1x = document.getElementById('cp1x');
            const cp1y = document.getElementById('cp1y');
            const cp2x = document.getElementById('cp2x');
            const cp2y = document.getElementById('cp2y');
            const endX = document.getElementById('endX');
            const endY = document.getElementById('endY');

            // 坐标标签
            // const startLabel = document.getElementById('startLabel');
            // const endLabel = document.getElementById('endLabel');
            // const control1Label = document.getElementById('control1Label');
            // const control2Label = document.getElementById('control2Label');

            const pathData = document.getElementById('pathData');
            const updateBtn = document.getElementById('updateBtn');

            // 更新曲线函数
            function updateCurve() {
                const sx = parseInt(startX.value);
                const sy = parseInt(startY.value);
                const x1 = parseInt(cp1x.value);
                const y1 = parseInt(cp1y.value);
                const x2 = parseInt(cp2x.value);
                const y2 = parseInt(cp2y.value);
                const ex = parseInt(endX.value);
                const ey = parseInt(endY.value);

                // 更新路径
                const newPath = `M${sx},${sy} C${x1},${y1} ${x2},${y2} ${ex},${ey}`;
                bezierCurve.setAttribute('d', newPath);

                // 更新点位置
                startPoint.setAttribute('cx', sx);
                startPoint.setAttribute('cy', sy);
                endPoint.setAttribute('cx', ex);
                endPoint.setAttribute('cy', ey);
                control1.setAttribute('cx', x1);
                control1.setAttribute('cy', y1);
                control2.setAttribute('cx', x2);
                control2.setAttribute('cy', y2);

                // 更新连线
                line1.setAttribute('x1', sx);
                line1.setAttribute('y1', sy);
                line1.setAttribute('x2', x1);
                line1.setAttribute('y2', y1);
                line2.setAttribute('x1', x2);
                line2.setAttribute('y1', y2);
                line2.setAttribute('x2', ex);
                line2.setAttribute('y2', ey);

                // 更新坐标标签
                // updateLabelPosition(startLabel, sx, sy);
                // updateLabelPosition(endLabel, ex, ey);
                // updateLabelPosition(control1Label, x1, y1);
                // updateLabelPosition(control2Label, x2, y2);

                // 更新标签文本
                // startLabel.firstElementChild.textContent = `(${sx}, ${sy})`;
                // endLabel.firstElementChild.textContent = `(${ex}, ${ey})`;
                // control1Label.firstElementChild.textContent = `(${x1}, ${y1})`;
                // control2Label.firstElementChild.textContent = `(${x2}, ${y2})`;

                // 更新显示的路径数据
                pathData.textContent = newPath;
            }

            // 更新标签位置（避免超出画布）
            function updateLabelPosition(label, x, y) {
                const svgWidth = 600;
                const svgHeight = 400;
                const labelWidth = 60;
                const labelHeight = 30;

                // 调整X位置
                let labelX = x;
                if (x + labelWidth > svgWidth) {
                    labelX = x - labelWidth;
                }

                // 调整Y位置
                let labelY = y;
                if (y + labelHeight > svgHeight) {
                    labelY = y - labelHeight;
                }

                label.setAttribute('x', labelX);
                label.setAttribute('y', labelY);
            }

            // 按钮点击事件
            updateBtn.addEventListener('click', updateCurve);

            // 输入框变化事件
            [startX, startY, cp1x, cp1y, cp2x, cp2y, endX, endY].forEach(input => {
                input.addEventListener('change', updateCurve);
                input.addEventListener('input', updateCurve);
            });

            // 拖拽功能
            function makeDraggable(element, xInput, yInput, isControlPoint = false) {
                let isDragging = false;

                element.addEventListener('mousedown', function (e) {
                    isDragging = true;
                    e.preventDefault(); // 防止文本选中
                });

                svg.addEventListener('mousemove', function (e) {
                    if (!isDragging) return;

                    const rect = svg.getBoundingClientRect();
                    const x = e.clientX - rect.left;
                    const y = e.clientY - rect.top;

                    // 限制在画布内
                    const boundedX = Math.max(0, Math.min(x, 600));
                    const boundedY = Math.max(0, Math.min(y, 400));

                    // 更新元素位置
                    element.setAttribute('cx', boundedX);
                    element.setAttribute('cy', boundedY);

                    // 更新输入框
                    xInput.value = Math.round(boundedX);
                    yInput.value = Math.round(boundedY);

                    // 如果是控制点，则更新连线
                    if (isControlPoint) {
                        updateCurve();
                    } else {
                        // 如果是起点或终点，需要更新所有相关元素
                        updateCurve();
                    }
                });

                document.addEventListener('mouseup', function () {
                    isDragging = false;
                });
            }

            // 使所有点可拖拽
            makeDraggable(startPoint, startX, startY);
            makeDraggable(endPoint, endX, endY);
            makeDraggable(control1, cp1x, cp1y, true);
            makeDraggable(control2, cp2x, cp2y, true);

            // 初始更新
            updateCurve();
        });
    </script>
</body>

</html>